import json

from decimal import Decimal
from django import http
from django.contrib.auth.mixins import LoginRequiredMixin
from django.db import transaction
from django.shortcuts import render

# Create your views here.
from django.utils import timezone
from django.views import View
from django_redis import get_redis_connection

from apps.goods.models import SKU
from apps.order.models import OrderInfo, OrderGoods
from apps.users.models import Address
from utils.response_code import RETCODE
from utils.views import LoginRequiredJSONMixin

# 展示结算订单
class placeOredrView(LoginRequiredMixin, View):
    """结算订单"""

    def get(self, request):
        """提供订单结算页面"""
        # 1.必须是登录用户才可以访问
        user = request.user
        # 2.获取登陆用户信息
        # 3.根据用户信息进行地址查询
        addressess = Address.objects.filter(user=user,is_deleted=False)
        # 4.获取redis中选中的商品id
        redis_conn = get_redis_connection('carts')
        sku_id_count = redis_conn.hgetall('carts_%s'%user.id)
        selected_ids = redis_conn.smembers('selected_%s'%user.id)
        selected_carts = {}
        for id in selected_ids:
            selected_carts[int(id)]=int(sku_id_count[id])
        ids = selected_carts.keys()

        # 5.对商品进行便利查询
        # 运费
        freight = 10
        #金额总计
        total_amount=0
        # 总数量
        total_count=0
        skus = []
        for id in ids:
            sku = SKU.objects.get(id=id)
            # 动态给对象添加属性
            # 数量
            sku.count = selected_carts[sku.id]
            # 金额小计
            sku.amount = (sku.price * sku.count)
            # 累加金额
            total_amount += sku.amount
            # 累加数量
            total_count += sku.count
            skus.append(sku)

        # 6.计算总金额  和总的实付额
        payment_amount = total_amount + freight

        context = {
            'addresses': addressess,
            'skus': skus,
            'freight': freight,
            'payment_amount': payment_amount,
            'total_count': total_count,
            'total_amount': total_amount
        }
        return render(request, 'place_order.html',context=context)



# 提交订单信息
class OrderCommitView(LoginRequiredJSONMixin, View):
    """提交订单"""

    def post(self, request):
        """保存订单信息和订单商品信息"""
        # 获取当前要保存的订单数据

        # 1.接收数据
        # 1.1 获取用户信息

        data = json.loads(request.body.decode())

        address_id = data.get('address_id')
        pay_method = data.get('pay_method')
        # 2.验证数据
        if not all([address_id, pay_method]):
            return http.JsonResponse({'code':RETCODE.PARAMERR})

            # 判断pay_method是否合法  是否是货到付款或者是支付宝支付
        if pay_method not in [OrderInfo.PAY_METHODS_ENUM['CASH'], OrderInfo.PAY_METHODS_ENUM['ALIPAY']]:
            return http.JsonResponse({'code':RETCODE.PARAMERR})

            # 3.数据入库
        # 1.先生成订单基本信息
        user = request.user

        # 1.2获取地址信息
        try:
            addresses = Address.objects.get(id=address_id )
        except Address.DoesNotExist:
            return http.JsonResponse({'code':RETCODE.PARAMERR})

        # 1.3 自己生成一个主键
        # 生成订单编号：年月日时分秒+用户编号
        order_id = timezone.localtime().strftime('%Y%m%d%H%M%S') + ('%09d' % user.id)
        # 1.4 总金额，总数量，运费
        total_amount = Decimal('0')
        total_count = 0
        freight = Decimal('10.00')
        # 1.5 支付方式
        if pay_method not in (OrderInfo.PAY_METHODS_ENUM['CASH'],OrderInfo.PAY_METHODS_ENUM['ALIPAY']):
            return http.JsonResponse({'code': RETCODE.PARAMERR})
        # 订单状态
        # 如果是货到付款   应该为待发货
        if pay_method == OrderInfo.PAY_METHODS_ENUM['CASH']:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        # 如果是支付宝  待支付
        else:
            status = OrderInfo.ORDER_STATUS_ENUM['UNPAID']

        with transaction.atomic():
        # 创建事务保存点  创建事物开始的点
            save_id = transaction.savepoint()
            # 1.6 订单状态
            order = OrderInfo.objects.create(
                order_id=order_id,
                user=user,
                address=addresses,
                total_count=0,
                total_amount=Decimal('0'),
                freight=Decimal('10.00'),
                pay_method=pay_method,
                status= status,
            )

            # 2.在生成订单商品信息
            # 	2.1 链接redis，获取hash数和set数据
            redis_conn = get_redis_connection('carts')
            redis_id_counts = redis_conn.hgetall('carts_%s'% user.id)
            selected_ids = redis_conn.smembers('selected_%s'%user.id)
            # 2.2 对redis数据进行类型转换，我们重新组织数据  组织成为一个  选中的数据 selected_carts={sku_id:count,...}
            selected_carts = {}
            for id in selected_ids:
                selected_carts[int(id)] = int(redis_id_counts[id])
            # 2.3 获取商品的ids，对id进行遍历查询
            ids = selected_carts.keys()
            # 	2.4 查询商品信息
            for id in ids:
                while True:
                    sku = SKU.objects.get(id=id)

                    # 读取原始库存



                    # 2.5 判断库存是否充足
                    buy_redis_count = selected_carts[sku.id]
                    if buy_redis_count > sku.stock:

                        # 库存不足  进行事务回滚
                        transaction.savepoint_rollback(save_id)

                        return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                    # 先记录库存
                    old_stock = sku.stock

                    # 乐观锁
                    new_stock = sku.stock - buy_redis_count
                    new_sales = sku.sales + buy_redis_count

                    rect = SKU.objects.filter(stock=old_stock, pk=sku.id).update(stock=new_stock, sales=new_sales)
                    # 返回一成功  返回0失败
                    if rect == 0:
                        transaction.savepoint_rollback(save_id)
                        return http.JsonResponse({'code': RETCODE.STOCKERR, 'errmsg': '库存不足'})
                 # #2.6 改变商品的库存和销量
                 #    sku.stock -= sku_count
                 #    sku.sales += sku_count
                 #    sku.save()

                    OrderGoods.objects.create(
                        order=order,
                        sku=sku,
                        count=buy_redis_count,
                        price=sku.price,
                    )
                # 保存商品订单中总价和总数量
                    order.total_count += buy_redis_count
                    order.total_amount += (buy_redis_count * sku.price)
                    # 添加邮费和保存订单信息
                    order.total_amount += order.freight

                    break
                order.save()
                #事务进行提交
                transaction.savepoint_commit(save_id)
                # return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '下单失败'})

                # 清除购物车中redis中已结算的商品信息
                # 删除hash数据
                redis_conn.hdel('carts_%s' % user.id, *selected_ids)
                # 移除列表数据
                redis_conn.srem('selected_%s' % user.id, *selected_ids)


                # 响应提交订单结果
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '下单成功', 'order_id':order_id,'payment_amount':order.total_amount})



# 订单提交成功
class OrderSuccessView(LoginRequiredMixin, View):
    """提交订单成功"""
    def get(self, request):
        # 获取订单 id
        order_id = request.GET.get('order_id')
        # 获取支付数量
        payment_amount = request.GET.get('payment_amount')
        # 支付方式
        pay_method = request.GET.get('pay_method')

        context = {
            'order_id':order_id,
            'payment_amount':payment_amount,
            'pay_method':pay_method
        }
        return render(request, 'order_success.html', context)


# 订单评价
class OrderJudgeView(View):
    def get(self, request):


        return render(request,'goods_judge.html')

